﻿using System;
using System.Windows.Forms;
using GeoSketch2.Core;
using System.Xml;
using System.Collections.Generic;
using System.Reflection;

namespace GeoSketch2.Archaeo
{
    /// <summary>
    /// The last subdivision of the main site
    /// </summary>
    public class _ExcavationUnit:BaseExcavationArea
    {
        #region XML
        
        #endregion

        #region Fields

        // <summary>
        /// The parent square
        // </summary>
        public ExcavationSquare ParentExcavationSquare;

        SurveyLogBook _SurveyLogBook;

        BaseSoilSheet _SoilSheet;
        #endregion

        #region Constructor
        /// <summary>
        /// The last subdivision of the main site
        /// </summary>
        /// <param name="ParentSquare">The parent square of the unit</param>
        public ExcavationUnit(ExcavationSquare ParentSquare)
            : this(ParentSquare.Name + "Unit" + ParentSquare.ExcavationUnits.Count, "", DateTime.Now, ParentSquare.Bounds.DeepClone(), new List<Layer>(), ParentSquare, null, ParentSquare.Project.SoilSheetModel.GetNew())
        {
            this.SurveyLogBook = new SurveyLogBook(this);
        }

        /// <summary>
        /// The last subdivision of the main site
        /// </summary>
        /// <param name="ParentSquare">The parent square of the unit</param>
        /// <param name="Name">The name of the square</param>
        /// <param name="ArchaeologistName">The name of the archaeologist</param>
        /// <param name="CreationTime">The time of creation</param>
        /// <param name="Bounds">The bounds of the area in object coordinates, Y-axis upside</param>
        /// <param name="AvailableLayers">The available layers from this area</param>
        /// <param name="LogBook">The logbook of the unit</param>
        /// <param name="SoilSheet">The soil description sheet</param>
        public ExcavationUnit(string Name, string ArchaeologistName, DateTime CreationTime, Point2D64D[] Bounds, List<Layer> AvailableLayers, ExcavationSquare ParentSquare, SurveyLogBook LogBook, BaseSoilSheet SoilSheet)
            : base(Name, ArchaeologistName, CreationTime, Bounds, AvailableLayers)
        {
            this.ParentExcavationSquare = ParentSquare;
            if (LogBook != null)
            {
                this.SurveyLogBook = LogBook;
            }
            this.SoilSheet = SoilSheet;

            this.ParentExcavationSquare.ExcavationUnits.Add(this);

            if (AvailableLayers.Count == 0)
            {
                Layer DefaultLayer = new Layer(Name + "DefaultLayer", Vars.Setup.StandardObjects.ExcavationAreas.ExcavationUnit.DefaultLayerColor, ParentSquare.Project.DefaultLineType, true);
                AvailableLayers.Add(DefaultLayer);
                Project.ProjectLayers.Add(DefaultLayer);
            }

            this.AreaTreeDepth = 2;
        }

        /// <summary>
        /// The last subdivision of the main site
        /// </summary>
        /// <param name="Xr">The XmlReader to read from</param>
        /// <param name="ParentSquare">The parent square of the unit</param>
        public ExcavationUnit(XmlReader Xr, ExcavationSquare ParentSquare)
            : base(Xr, ParentSquare.ParentExcavationSite)
        {
            this.ParentExcavationSquare = ParentSquare;
            this.ParentExcavationSquare.ExcavationUnits.Add(this);

            if (AvailableLayers.Count == 0)
            {
                Layer DefaultLayer = new Layer(Name + "DefaultLayer", Vars.Setup.StandardObjects.ExcavationAreas.ExcavationUnit.DefaultLayerColor, Project.DefaultLineType, true);
                AvailableLayers.Add(DefaultLayer);
                Project.ProjectLayers.Add(DefaultLayer);
            }

            Xr.ReadToFollowing(XML_SpecificInfos);

            Xr.ReadToFollowing(BaseSoilSheet.XML_SoilSheet);

            Xr.ReadToFollowing(BaseSoilSheet.XML_Template);
            
            this.SoilSheet = (BaseSoilSheet)Type.GetType(Xr.ReadString()).InvokeMember(null,BindingFlags.CreateInstance, null, null, new object[] {Xr });

            Xr.ReadEndElement();

            Xr.ReadEndElement();
        }
        #endregion

        #region Methods
        /// <summary>
        /// Writes the object to a file
        /// </summary>
        /// <param name="Xw">The XmlWriter to write to</param>
        public void ToFile(XmlWriter Xw)
        {
            Xw.WriteStartElement(this.GetType().FullName);

            #region Unit Base Information
            Xw.WriteStartElement(XML_BaseInfos);

            #region Unit Name
            Xw.WriteStartElement(XML_Name);
            Xw.WriteString(this.Name);
            Xw.WriteEndElement();
            #endregion

            #region Unit Creation Date
            Xw.WriteStartElement(XML_CreationDate);
            Xw.WriteString(this.CreationTime.ToBinary().ToString(Core.Vars.Setup.GeoSketch.NumberFormat));
            Xw.WriteEndElement();
            #endregion

            #region Unit Archaeologist Name
            Xw.WriteStartElement(XML_Archaeologist);
            Xw.WriteString(this.ArchaeologistName);
            Xw.WriteEndElement();
            #endregion

            #region Unit Bounds
            Xw.WriteStartElement(XML_Bounds);
            foreach (Point2D64D p in this.Bounds)
            {
                p.ToFile(Xw);
            }
            Xw.WriteEndElement();
            #endregion

            #region Unit Available Layers
            Xw.WriteStartElement(XML_AvailableLayers);
            foreach (Layer l in this.AvailableLayers)
            {
                Xw.WriteStartElement(Layer.XML_Name);
                Xw.WriteString(l.Name);
                Xw.WriteEndElement();
            }
            Xw.WriteEndElement();
            #endregion

            Xw.WriteEndElement();
            #endregion

            #region Unit Specific Information
            Xw.WriteStartElement(XML_SpecificInfos);

            #region SoilSheet
            this.SoilSheet.ToFile(Xw);
            #endregion

            Xw.WriteEndElement();
            #endregion

            Xw.WriteEndElement();
        } 
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the digging height of the unit
        /// </summary>
        public override DiggingHeight DiggingHeight
        {
            get
            {
                Archaeo.DiggingHeight dst = new DiggingHeight();
                dst.MaxHeight = double.MinValue;
                dst.MinHeight = double.MaxValue;

                foreach (BaseArchaeoDrawableObject obj in Project.ArchaeoObjects)
                {
                    if (obj.ExcavationUnit == this)
                    {
                        if (obj.GetType() == typeof(Benchmark))
                        {
                            dst.MinHeight = Math.Min(dst.MinHeight, ((Benchmark)obj).Altitude);
                            dst.MaxHeight = Math.Max(dst.MaxHeight, ((Benchmark)obj).Altitude);
                        }
                    }
                }

                return dst;
            }
        }

        /// <summary>
        /// Gets the treeview node of the area
        /// </summary>
        public override TreeNode TreeViewNode
        {
            get
            {
                TreeNode node = new TreeNode(Name, Vars.Setup.Forms.DrawingForm.TreeViewUnitImageIndex, Vars.Setup.Forms.DrawingForm.TreeViewUnitImageIndex);
                node.Tag = this;
                return node;
            }
        }

        /// <summary>
        /// Gets the path of the area, the path from the main excavation site
        /// </summary>
        public override string Path
        {
            get
            {
                return ParentExcavationSquare.Path+" - "+Name;
            }
        }

        /// <summary>
        /// Gets or sets the soil description sheet
        /// </summary>
        public BaseSoilSheet SoilSheet
        {
            get
            {
                return _SoilSheet;
            }
            set
            {
                _SoilSheet = value;
                _SoilSheet.Unit = this;
            }
        }

        /// <summary>
        /// Gets or sets survey logbook
        /// </summary>
        public SurveyLogBook SurveyLogBook
        {
            get
            {
                return _SurveyLogBook;
            }
            set
            {
                _SurveyLogBook = value;
                _SurveyLogBook.Unit = this;
            }
        }
        #endregion
    }
}
